﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FinanSoft.Utilities;
using FinanSoft.Entities;
using System.Xml;
using FinanSoft.BusinessLayer;
using System.Data.SqlClient;

namespace FinanSoft.DataLayer
{
    class ConfigurationDataManager
    {
        #region Singleton

        private ConfigurationDataManager()
        {}
        /// <summary>
        /// Unica Instancia de esa clase
        /// </suammary>
        private static ConfigurationDataManager _instance;

        /// <summary>
        /// Metodo para implementar el patrón singleton
        /// </summary>
        /// <returns>Instancia única de la clase</returns>
        public static ConfigurationDataManager GetInstance() 
        {
            if (_instance == null)
                _instance = new ConfigurationDataManager();
            return _instance;
        }
        #endregion 

        #region Métodos
        public int AddTax(string name, string code, float percentage)
        {
            try
            {
                AppConfigReader appConfig = AppConfigReader.GetInstance();
                string spName = Constants.SP_NAME_ADD_TAX;
                SqlParameter[] parameters = {
                        new SqlParameter(Constants.SP_PARAM_ADD_TAX_NAME, name),
                        new SqlParameter(Constants.SP_PARAM_ADD_TAX_CODE, code),
                        new SqlParameter(Constants.SP_PARAM_ADD_TAX_PERCENTAGE, percentage)
                                            };
                SqlDataHelper dataHelper = new SqlDataHelper(appConfig.GetConnectionString(Constants.DB_CONN));
                SqlDataReader result = dataHelper.ExecuteStoredProcedure(spName, parameters);
                while (result.Read())
                    return Convert.ToInt32(result[0]);
                dataHelper.CloseReader();
                return Constants.INVALID_ID;
            }
            catch (Exception ex)
            {
                return Constants.INVALID_ID;
            }
        }

        public bool DeleteTax(int id)
        {
            try
            {
                AppConfigReader appConfig = AppConfigReader.GetInstance();
                string spName = Constants.SP_NAME_DELETE_TAX;
                SqlParameter[] parameters = {
                        new SqlParameter(Constants.SP_PARAM_DELETE_TAX_ID, id)
                                            };
                SqlDataHelper dataHelper = new SqlDataHelper(appConfig.GetConnectionString(Constants.DB_CONN));
                dataHelper.ExecuteNoResultStoredProcedure(spName, parameters);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// Obtiene todas los impuestos de la base de datos
        /// </summary>
        /// <returns>El objeto lista de impuestos</returns>
        public List<Tax> GetTaxes()
        {
            List<Tax> ImpuestoList;

            try
            {
                ImpuestoList = new List<Tax>();
                AppConfigReader appConfig = AppConfigReader.GetInstance();
                string spName = Constants.SP_NAME_GET_IMPUESTOS;
                SqlParameter[] parameters = new SqlParameter[0];
                SqlDataHelper dataHelper = new SqlDataHelper(appConfig.GetConnectionString(Constants.DB_CONN));
                SqlDataReader result = dataHelper.ExecuteStoredProcedure(spName, parameters);
                while (result.Read())
                {
                    int idTipoImpuesto = System.Convert.ToInt32(result[Constants.SP_COLUMN_GET_IMPUESTO_ID_TYPE_IMP]);
                    String name = (string)result[Constants.SP_COLUMN_GET_IMPUESTO_NOMBRE];
                    String acronimo = (string)result[Constants.SP_COLUMN_GET_IMPUESTO_ACRONIMO];
                    float porcentaje = (float)System.Convert.ToDouble(result[Constants.SP_COLUMN_GET_IMPUESTO_PORC]);

                    ImpuestoList.Add(new Tax(idTipoImpuesto, name, acronimo, porcentaje));
                }
                dataHelper.CloseReader();
                return ImpuestoList;
            }
            catch (Exception ex)
            {
                return null;
            }
        }
 
        /// <summary>
        /// Método que se encarga de leer las lista de tipos especiales de cuentas de la base de datos y mandar
        /// a parsear el xml que el stored procedure devuelve para convertirlo en un objeto
        /// de tipo SpecialAccount
        /// </summary>
        /// <returns>Retorna el objeto cuentas especiales</returns>
        public SpecialAccount[] GetSpecialAccountType()
        {
            
            try
            {
                AppConfigReader appConfig = AppConfigReader.GetInstance();
                string spName = Constants.SP_NAME_GET_SPECIAL_ACCOUNTS_TYPE;
                SqlParameter[] parameters = new SqlParameter[0];
                SqlDataHelper dataHelper = new SqlDataHelper(appConfig.GetConnectionString(Constants.DB_CONN));
                SqlDataReader result = dataHelper.ExecuteStoredProcedure(spName, parameters);
                if (result.HasRows)
                {
                    result.Read();
                    string xmlString = result.GetString(0);
                    dataHelper.CloseReader();
                    xmlString = Constants.ROOT_NODE_BEGINNING + xmlString + Constants.ROOT_NODE_ENDING;
                    
                    // Se crea un documento XML con el string recibido
                    XmlDocument xmlSpecAccount = new XmlDocument();

                    xmlSpecAccount.LoadXml(xmlString);
                    return BuildxmlSpecAccountType(xmlSpecAccount);
                }
                else
                    return new SpecialAccount[0];
            }
            catch (Exception ex)
            {
                return null;
            }

            //String xmlString = "<Cuenta IdCuenta='1' Nombre='1. Activos' NombreExtranjero='Activos' EsTitulo='1' IdMoneda='2' Tipo='Activos' Codigo='100000'><Cuenta IdCuenta='21' Nombre='1-10. Activos circulantes' NombreExtranjero='Activos circulantes' EsTitulo='1' IdMoneda='2' Tipo='Activos' Codigo='110000'><Cuenta IdCuenta='24' Nombre='1-10-100 Bancos' NombreExtranjero='Bancos' EsTitulo='0' IdMoneda='2' Tipo='Activos' Codigo='111000' MontoLocal='2120000.0000' MontoSistema='4000.0000' /></Cuenta></Cuenta><Cuenta IdCuenta='10' Nombre='2. Pasivos' NombreExtranjero='Pasivos' EsTitulo='1' IdMoneda='2' Tipo='Pasivos' Codigo='200000'><Cuenta IdCuenta='25' Nombre='2-10. Deudas corto plazo' NombreExtranjero='Deudas corto plazo' EsTitulo='0' IdMoneda='2' Tipo='Pasivos' Codigo='210000' MontoLocal='2120000.0000' MontoSistema='4000.0000' /></Cuenta><Cuenta IdCuenta='12' Nombre='3. Patrimonio' NombreExtranjero='Patrimonio' EsTitulo='1' IdMoneda='2' Tipo='Capital' Codigo='300000' /><Cuenta IdCuenta='13' Nombre='4. Ingresos' NombreExtranjero='Ingresos' EsTitulo='1' IdMoneda='2' Tipo='Ingresos' Codigo='400000' /><Cuenta IdCuenta='14' Nombre='5. Costos' NombreExtranjero='Costos' EsTitulo='1' IdMoneda='2' Tipo='Gastos' Codigo='500000' /><Cuenta IdCuenta='15' Nombre='6. Gastos' NombreExtranjero='Gastos' EsTitulo='1' IdMoneda='2' Tipo='Gastos' Codigo='600000' /><Cuenta IdCuenta='19' Nombre='7. Otros ingresos' NombreExtranjero='Otros ingresos' EsTitulo='1' IdMoneda='2' Tipo='Ingresos' Codigo='700000' /><Cuenta IdCuenta='20' Nombre='8. Otros gastos' NombreExtranjero='Otros gastos' EsTitulo='1' IdMoneda='2' Tipo='Gastos' Codigo='800000' />";
        }

        /// <summary>
        /// Método que se encarga de leer las lista de tipos cuentas asignadas como un tipo de
        /// cuenta especial de la base de datos y mandar a parsear el xml que el stored procedure 
        /// devuelve para convertirlo en un objeto de tipo SpecialAccount
        /// </summary>
        /// <returns>Retorna el objeto cuentas especiales</returns>
        public SpecialAccount[] GetSpecialAccount(int idTipoCtaEsp)
        {

            try
            {
                AppConfigReader appConfig = AppConfigReader.GetInstance();
                string spName = Constants.SP_NAME_GET_SPECIAL_ACCOUNT;
                SqlParameter[] parameters = new SqlParameter[1];
                parameters[0] = new SqlParameter(Constants.SP_PARAM_SPECIAL_ACCOUNT_ID, idTipoCtaEsp);
                Console.WriteLine(parameters[0]);
                Console.WriteLine(Constants.SP_PARAM_SPECIAL_ACCOUNT_ID + " *** " + idTipoCtaEsp);
                SqlDataHelper dataHelper = new SqlDataHelper(appConfig.GetConnectionString(Constants.DB_CONN));
                SqlDataReader result = dataHelper.ExecuteStoredProcedure(spName, parameters);
                if (result.HasRows)
                {
                    result.Read();
                    string xmlString = result.GetString(0);
                    dataHelper.CloseReader();
                    xmlString = Constants.ROOT_NODE_BEGINNING + xmlString + Constants.ROOT_NODE_ENDING;

                    // Se crea un documento XML con el string recibido
                    XmlDocument xmlSpecAccount = new XmlDocument();

                    xmlSpecAccount.LoadXml(xmlString);
                    return BuildxmlSpecAccount(xmlSpecAccount);
                }
                else
                    return new SpecialAccount[0];
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        /// <summary>
        /// Método que se encarga de leer las lista de tipos cuentas NO asignadas como un tipo de
        /// cuenta especial de la base de datos y mandar a parsear el xml que el stored procedure 
        /// devuelve para convertirlo en un objeto de tipo SpecialAccount
        /// </summary>
        /// <returns>Retorna el objeto cuentas especiales</returns>
        public SpecialAccount[] GetNotSpecialAccount(int idTipoCtaEsp)
        {

            try
            {
                AppConfigReader appConfig = AppConfigReader.GetInstance();
                string spName = Constants.SP_NAME_GET_NOT_SPECIAL_ACCOUNT;
                SqlParameter[] parameters = new SqlParameter[1];
                parameters[0] = new SqlParameter(Constants.SP_PARAM_NOT_SPECIAL_ACCOUNT_ID, idTipoCtaEsp);
                SqlDataHelper dataHelper = new SqlDataHelper(appConfig.GetConnectionString(Constants.DB_CONN));
                SqlDataReader result = dataHelper.ExecuteStoredProcedure(spName, parameters);
                if (result.HasRows)
                {
                    result.Read();
                    string xmlString = result.GetString(0);
                    dataHelper.CloseReader();
                    xmlString = Constants.ROOT_NODE_BEGINNING + xmlString + Constants.ROOT_NODE_ENDING;

                    // Se crea un documento XML con el string recibido
                    XmlDocument xmlSpecAccount = new XmlDocument();

                    xmlSpecAccount.LoadXml(xmlString);
                    return BuildxmlSpecAccount(xmlSpecAccount);
                }
                else
                    return new SpecialAccount[0];
            }
            catch (Exception ex)
            {
                return null;
            }
        }        

        /// <summary>
        /// Método que recibe el documento xml a parsear para convertirlo en un SpecialAccount
        /// </summary>
        /// <param name="xmlPeriod">es el string xml a parsear</param>
        /// <returns>retorna un arreglo de todos los tipos de cuentas especiales</returns>
        public SpecialAccount[] BuildxmlSpecAccountType(XmlDocument xmlSpecAccount)
        {
            
            // Aquí llamo a la clase de la base de datos que me regresa el string
            //String xmlString = "";
            XmlNodeList nodeChildren = xmlSpecAccount.FirstChild.ChildNodes;

            SpecialAccount[] arraySpecAccount = new SpecialAccount[nodeChildren.Count];
            

            // Por cada nodo principal
            int periodIndex = 0;
            
            foreach (XmlNode node in nodeChildren)
            {


                SpecialAccount SpecAccount = new SpecialAccount();
                
                SpecAccount.Id = System.Convert.ToInt32(node.Attributes.GetNamedItem(Constants.TAG_NAME_SPECIAL_ACCOUNT_ID).Value);
                SpecAccount.Name = node.Attributes.GetNamedItem(Constants.TAG_NAME_SPECIAL_ACCOUNT_NOMBRE).Value;
                
                arraySpecAccount[periodIndex] = SpecAccount;
                periodIndex++;

            }
            
            return arraySpecAccount;
        }

        public SpecialAccount[] BuildxmlSpecAccount(XmlDocument xmlSpecAccount)
        {

            // Aquí llamo a la clase de la base de datos que me regresa el string
            //String xmlString = "";
            XmlNodeList nodeChildren = xmlSpecAccount.FirstChild.ChildNodes;

            SpecialAccount[] arraySpecAccount = new SpecialAccount[nodeChildren.Count];


            // Por cada nodo principal
            int periodIndex = 0;

            foreach (XmlNode node in nodeChildren)
            {


                SpecialAccount SpecAccount = new SpecialAccount();

                SpecAccount.idCuenta = System.Convert.ToInt32(node.Attributes.GetNamedItem(Constants.TAG_NAME_SPECIAL_ACCOUNT_IDCTA).Value);
                SpecAccount.Name = node.Attributes.GetNamedItem(Constants.TAG_NAME_SPECIAL_ACCOUNT_NOMBRE).Value;

                arraySpecAccount[periodIndex] = SpecAccount;
                periodIndex++;

            }

            return arraySpecAccount;
        }

        /// <summary>
        /// Agrega un una nueva cuenta a un tipo especial de cuenta
        /// </summary>
        /// <param name="newPeriod">Cuenta Especial con idTipo, idCuenta</param>
        /// <returns>retorna exito si se introdujo a la base de datos</returns>
        public bool CreateNewSpecialAccount(SpecialAccount nuevaCta)
        {
            try
            {
                AppConfigReader appConfig = AppConfigReader.GetInstance();
                string spName = Constants.SP_NAME_NEW_SPECIAL_ACCOUNT;
                //@idTipoCuentaEsp TINYINT, @idCuenta INT
                SqlParameter[] parameters = new SqlParameter[2];
                parameters[0] = new SqlParameter(Constants.SP_PARAM_ADD_SPECIAL_ACCOUNT_ID_TIPO, nuevaCta.Id);
                parameters[1] = new SqlParameter(Constants.SP_PARAM_ADD_SPECIAL_ACCOUNT_ID_CTA, nuevaCta.idCuenta);
                Console.WriteLine(parameters[0]);
                Console.WriteLine(Constants.SP_PARAM_ADD_SPECIAL_ACCOUNT_ID_TIPO + " *** " + nuevaCta.Id);
                Console.WriteLine(Constants.SP_PARAM_ADD_SPECIAL_ACCOUNT_ID_CTA + " *** " + nuevaCta.idCuenta);          
                SqlDataHelper dataHelper = new SqlDataHelper(appConfig.GetConnectionString(Constants.DB_CONN));

                SqlDataReader result = dataHelper.ExecuteStoredProcedure(spName, parameters);

                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// Elimina un una nueva cuenta de un tipo especial de cuenta
        /// </summary>
        /// <param name="newPeriod">Cuenta Especial con idTipo, idCuenta</param>
        /// <returns>retorna exito si se eliminó a la base de datos</returns>
        public bool DeleteNewSpecialAccount(SpecialAccount nuevaCta)
        {
            try
            {
                AppConfigReader appConfig = AppConfigReader.GetInstance();
                string spName = Constants.SP_NAME_DELETE_SPECIAL_ACCOUNT;
                //@idTipoCuentaEsp TINYINT, @idCuenta INT
                SqlParameter[] parameters = new SqlParameter[2];
                parameters[0] = new SqlParameter(Constants.SP_PARAM_DELETE_SPECIAL_ACCOUNT_ID_TIPO, nuevaCta.Id);
                parameters[1] = new SqlParameter(Constants.SP_PARAM_DELETE_SPECIAL_ACCOUNT_ID_CTA, nuevaCta.idCuenta);
                Console.WriteLine(parameters[0]);
                Console.WriteLine(Constants.SP_PARAM_DELETE_SPECIAL_ACCOUNT_ID_TIPO + " *** " + nuevaCta.Id);
                Console.WriteLine(Constants.SP_PARAM_DELETE_SPECIAL_ACCOUNT_ID_CTA + " *** " + nuevaCta.idCuenta);
                SqlDataHelper dataHelper = new SqlDataHelper(appConfig.GetConnectionString(Constants.DB_CONN));

                SqlDataReader result = dataHelper.ExecuteStoredProcedure(spName, parameters);

                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        #endregion
    }
}
